package com.intelligent.system.auth.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.intelligent.system.auth.dto.*;
import com.intelligent.system.auth.entity.Menu;
import com.intelligent.system.auth.entity.Role;
import com.intelligent.system.auth.entity.RoleMenu;
import com.intelligent.system.auth.mapper.MenuMapper;
import com.intelligent.system.auth.mapper.RoleMapper;
import com.intelligent.system.auth.mapper.RoleMenuMapper;
import com.intelligent.system.auth.service.IMenuService;
import com.intelligent.system.auth.service.IRoleService;
import com.intelligent.system.common.exception.CustomException;
import com.intelligent.system.common.response.ResponseCode;
import com.intelligent.system.common.response.ResultDO;
import com.intelligent.system.common.utils.SnowflakeIdUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService {

    @Resource
    private MenuMapper menuMapper;

    @Resource
    private RoleMenuMapper roleMenuMapper;

    @Resource
    private IMenuService menuService;

    @Resource
    private SnowflakeIdUtils idUtils;

    @Override
    public ResultDO<RoleDTO> getRoleById(Long id) {
        try {
            Role role = this.getById(id);
            if (role == null) {
                log.error("未找到ID为 {} 的角色", id);
                throw new CustomException("角色不存在", ResponseCode.ROLE_NOT_FOUND.getCode());
            }
            RoleDTO roleDTO = new RoleDTO();
            BeanUtils.copyProperties(role, roleDTO);
            
            // 获取所有菜单并标记选中状态
            List<Menu> allMenus = menuMapper.selectList(null);
            List<RoleMenu> roleMenus = roleMenuMapper.selectList(
                Wrappers.<RoleMenu>lambdaQuery()
                    .eq(RoleMenu::getRoleId, id)
            );
            Set<Long> assignedMenuIds = roleMenus.stream()
                .map(RoleMenu::getMenuId)
                .collect(Collectors.toSet());
            
            // 构建菜单树并标记选中状态
            List<MenuWithRoleDTO> menuTree = buildMenuTree(allMenus, assignedMenuIds);
            roleDTO.setMenus(menuTree);
            
            return ResultDO.success(roleDTO);
        } catch (Exception e) {
            log.error("获取角色失败，ID: {}", id, e);
            throw new CustomException("系统错误", ResponseCode.SYSTEM_ERROR.getCode());
        }
    }

    @Override
    public ResultDO<List<RoleDTO>> getRoleList(RoleQueryDTO param) {
        try {

            LambdaQueryWrapper<Role> wrapper = new LambdaQueryWrapper<>();
            
            // 添加查询条件
            if (StringUtils.hasText(param.getRoleName())) {
                wrapper.like(Role::getRoleName, param.getRoleName());
            }
            if (param.getStatus() != null) {
                wrapper.eq(Role::getStatus, param.getStatus());
            }
            
            // 执行分页查询
            List<Role> results = this.list(wrapper);

            List<RoleDTO> dtoList = results.stream()
                    .map(role -> {
                        RoleDTO dto = new RoleDTO();
                        BeanUtils.copyProperties(role, dto);
                        
                        // 获取所有菜单并标记选中状态
                        List<Menu> allMenus = menuMapper.selectList(null);
                        List<RoleMenu> roleMenus = roleMenuMapper.selectList(
                            Wrappers.<RoleMenu>lambdaQuery()
                                .eq(RoleMenu::getRoleId, role.getRoleId())
                        );
                        Set<Long> assignedMenuIds = roleMenus.stream()
                            .map(RoleMenu::getMenuId)
                            .collect(Collectors.toSet());
                        
                        // 构建菜单树并标记选中状态
                        List<MenuWithRoleDTO> menuTree = buildMenuTree(allMenus, assignedMenuIds);
                        dto.setMenus(menuTree);
                            
                        return dto;
                    })
                    .collect(Collectors.toList());

            return ResultDO.success(dtoList);
        } catch (Exception e) {
            log.error("获取角色列表失败，参数: {}", param, e);
            throw new CustomException("系统错误", ResponseCode.SYSTEM_ERROR.getCode());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDO<?> addRole(RoleDTO param) {
        try {
            // 检查角色名是否已存在
            if (this.checkRoleNameExists(param.getRoleName())) {
                log.error("角色名已存在: {}", param.getRoleName());
                throw new CustomException("角色名已存在", ResponseCode.ROLE_ALREADY_EXISTS.getCode());
            }

            // 保存角色基本信息
            Role role = new Role();
            BeanUtils.copyProperties(param, role);
            role.setRoleId(idUtils.nextId());
            if (!this.save(role)) {
                throw new CustomException("保存角色失败", ResponseCode.SYSTEM_ERROR.getCode());
            }

            // 保存角色-菜单关联关系
            if (param.getMenuIds() != null && !param.getMenuIds().isEmpty()) {
                List<RoleMenu> roleMenus = param.getMenuIds().stream()
                    .map(menuId -> {
                        RoleMenu roleMenu = new RoleMenu();
                        roleMenu.setRoleId(role.getRoleId());
                        roleMenu.setMenuId(menuId);
                        return roleMenu;
                    })
                    .collect(Collectors.toList());

                // 批量保存角色-菜单关联
                for (RoleMenu roleMenu : roleMenus) {
                    roleMenu.setId(idUtils.nextId());
                    if (roleMenuMapper.insert(roleMenu) <= 0) {
                        throw new CustomException("保存角色菜单关联失败", ResponseCode.SYSTEM_ERROR.getCode());
                    }
                }
            }

            return ResultDO.success(null);
        } catch (CustomException e) {
            throw e;
        } catch (Exception e) {
            log.error("添加角色失败: {}", param, e);
            throw new CustomException("系统错误", ResponseCode.SYSTEM_ERROR.getCode());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDO<?> updateRole(RoleDTO param) {
        try {
            Role role = this.getById(param.getRoleId());
            if (role == null) {
                log.error("未找到ID为 {} 的角色", param.getRoleId());
                throw new CustomException("角色不存在", ResponseCode.ROLE_NOT_FOUND.getCode());
            }

            // 如果修改了角色名，需要检查是否已存在
            if (!role.getRoleName().equals(param.getRoleName()) 
                    && this.checkRoleNameExists(param.getRoleName())) {
                log.error("角色名已存在: {}", param.getRoleName());
                throw new CustomException("角色名已存在", ResponseCode.ROLE_ALREADY_EXISTS.getCode());
            }

            BeanUtils.copyProperties(param, role);
            if (this.updateById(role)) {
                return ResultDO.success(null);
            }
            throw new CustomException("系统错误", ResponseCode.SYSTEM_ERROR.getCode());
        } catch (CustomException e) {
            throw e;
        } catch (Exception e) {
            log.error("更新角色失败: {}", param, e);
            throw new CustomException("系统错误", ResponseCode.SYSTEM_ERROR.getCode());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDO<?> updateRoleStatus(Long roleId, Byte status) {
        try {
            Role role = this.getById(roleId);
            if (role == null) {
                log.error("未找到ID为 {} 的角色", roleId);
                throw new CustomException("角色不存在", ResponseCode.ROLE_NOT_FOUND.getCode());
            }

            role.setStatus(status);
            if (this.updateById(role)) {
                return ResultDO.success(null);
            }
            throw new CustomException("系统错误", ResponseCode.SYSTEM_ERROR.getCode());
        } catch (CustomException e) {
            throw e;
        } catch (Exception e) {
            log.error("更新角色状态失败: roleId={}, status={}", roleId, status, e);
            throw new CustomException("系统错误", ResponseCode.SYSTEM_ERROR.getCode());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDO<?> deleteRoleById(Long roleId) {
        try {
            if (!this.removeById(roleId)) {
                log.error("删除角色失败: {}", roleId);
                throw new CustomException("系统错误", ResponseCode.SYSTEM_ERROR.getCode());
            }
            this.roleMenuMapper.delete(Wrappers.<RoleMenu>lambdaQuery().eq(RoleMenu::getRoleId, roleId));
            return ResultDO.success(null);
        } catch (CustomException e) {
            throw e;
        } catch (Exception e) {
            log.error("删除角色失败: {}", roleId, e);
            throw new CustomException("系统错误", ResponseCode.SYSTEM_ERROR.getCode());
        }
    }

    @Override
    public ResultDO<List<MenuWithRoleDTO>> getRoleMenus(Long roleId) {
        try {
            // 1. 检查角色是否存在
            Role role = this.getById(roleId);
            if (role == null) {
                log.error("未找到ID为 {} 的角色", roleId);
                throw new CustomException("角色不存在", ResponseCode.ROLE_NOT_FOUND.getCode());
            }

            // 2. 获取所有菜单
            List<Menu> allMenus = menuMapper.selectList(null);

            // 3. 获取角色已分配的菜单ID列表
            List<RoleMenu> roleMenus = roleMenuMapper.selectList(
                    Wrappers.<RoleMenu>lambdaQuery()
                            .eq(RoleMenu::getRoleId, roleId)
            );
            Set<Long> assignedMenuIds = roleMenus.stream()
                    .map(RoleMenu::getMenuId)
                    .collect(Collectors.toSet());

            // 4. 构建菜单树并标记选中状态
            List<MenuWithRoleDTO> menuTree = buildMenuTree(allMenus, assignedMenuIds);

            return ResultDO.success(menuTree);
        } catch (CustomException e) {
            throw e;
        } catch (Exception e) {
            log.error("获取角色菜单列表失败: roleId={}", roleId, e);
            throw new CustomException("系统错误", ResponseCode.SYSTEM_ERROR.getCode());
        }
    }

    /**
     * 构建菜单树并标记选中状态
     * @param menus 所有菜单列表
     * @param assignedMenuIds 角色已分配的菜单ID集合
     * @return 菜单树
     */
    private List<MenuWithRoleDTO> buildMenuTree(List<Menu> menus, Set<Long> assignedMenuIds) {
        // 1. 转换为DTO并标记选中状态
        List<MenuWithRoleDTO> menuDTOs = menus.stream()
                .map(menu -> {
                    MenuWithRoleDTO dto = new MenuWithRoleDTO();
                    dto.setMenuId(menu.getMenuId());
                    dto.setParentId(menu.getParentId());
                    dto.setMenuName(menu.getMenuName());
                    dto.setUrl(menu.getUrl());
                    dto.setIcon(menu.getIcon());
                    dto.setOrderNum(menu.getOrderNum());
                    dto.setSelected(assignedMenuIds.contains(menu.getMenuId()));
                    dto.setChildren(new ArrayList<>());
                    return dto;
                })
                .collect(Collectors.toList());

        // 2. 构建菜单树
        Map<Long, List<MenuWithRoleDTO>> menuMap = menuDTOs.stream()
                .collect(Collectors.groupingBy(MenuWithRoleDTO::getParentId));

        // 3. 设置子菜单
        menuDTOs.forEach(menu -> {
            List<MenuWithRoleDTO> children = menuMap.get(menu.getMenuId());
            if (children != null) {
                menu.setChildren(children);
            }
        });

        // 4. 返回顶层菜单
        return menuDTOs.stream()
                .filter(menu -> menu.getParentId() == null || menu.getParentId() == 0)
                .collect(Collectors.toList());
    }

    private boolean checkRoleNameExists(String roleName) {
        LambdaQueryWrapper<Role> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Role::getRoleName, roleName);
        return this.count(wrapper) > 0;
    }
} 